﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using Medora.DataContract;

namespace Medora.Data.Helpers
{
    /// <summary>
    /// A maker of Repositories.
    /// </summary>
    /// <remarks>An instance of this class contains repository factory functions for different types.
    /// Each factory function takes an EF <see cref="DbContext" /> and returns
    /// a repository bound to that DbContext.
    /// <para>
    /// Designed to be a "Singleton", configured at web application start with
    /// all of the factory functions needed to create any type of repository.
    /// Should be thread-safe to use because it is configured at app start,
    /// before any request for a factory, and should be immutable thereafter.
    /// </para></remarks>
    public class RepositoryFactories
    {
      
        public RepositoryFactories(IDictionary<Type, Func<DbContext, object>> factories)
        {
            _repositoryFactories = factories;
        }


        /// <summary>
        /// Constructor that initializes with runtime  repository factories
        /// </summary>
        public RepositoryFactories()
        {
            _repositoryFactories = GetFactories();
        }


        private IDictionary<Type, Func<DbContext, object>> GetFactories()
        {
            return new Dictionary<Type, Func<DbContext, object>>
                {
                      {typeof(IProviderRepository), dbContext => new ProviderRepository(dbContext)},
                      {typeof(IPersonRepository), dbContext => new PersonRepository(dbContext)},
                      {typeof(IVisitRepository), dbContext => new VisitRepository(dbContext)},
                      {typeof(IScheduleItemRepository), dbContext => new ScheduleItemRepository(dbContext)}
                };
        }



        /// <summary>
        /// Get the repository factory function for the type.
        /// </summary>
        /// <typeparam name="T">Type serving as the repository factory lookup key.</typeparam>
        /// <returns>The repository function if found, else null.</returns>
        public Func<DbContext, object> GetRepositoryFactory<T>()
        {

            Func<DbContext, object> factory;
            _repositoryFactories.TryGetValue(typeof(T), out factory);
            return factory;
        }

       public Func<DbContext, object> GetRepositoryFactoryForEntityType<T>() where T : class
        {
            return GetRepositoryFactory<T>() ?? DefaultEntityRepositoryFactory<T>();
        }

        protected virtual Func<DbContext, object> DefaultEntityRepositoryFactory<T>() where T : class
        {
            return dbContext => new EFRepository<T>(dbContext);
        }

        private readonly IDictionary<Type, Func<DbContext, object>> _repositoryFactories;

    }
}